#!/usr/local/bin/python3
# *_* coding: UTF-8 *_*
# @IDE: PyCharm
# @Version: Python3.7
# @Author: Kendrick.Kc
# @Email: 509556985@qq.com
# @File: middle.py
# @Inst: 这里是模块名描述
# @Time: 2023/7/22 15:43
# -----


import django

django.setup()
from basic.models import ProcessNumber
from utils.timestamp import now_time_stamp

import time
import traceback
import datetime
import pandas
import pandas_ta

pandas.set_option('expand_frame_repr', False)  # 当列太多时不换行
pandas.set_option('display.max_rows', 10000)  # 最多显示数据的行数


class Middle:

    def __init__(self, binance):
        self.binance = binance
        self.symbol = self.binance.parameter.symbol
        self.data = {
            "price": None,   # 最新价格
            "shang_gui": None,  # 上轨价格
            "xia_gui": None,  # 下轨价格
            "rsi": None     # rsi值
        }
        self.is_exit = True  # 当前交易对是否继续交易
        self.res_db = self.binance.cache_get(self.binance.parameter.db_coll)
        self.strategy_start()

    def strategy_start(self, num=0):
        """ 交易开始的操作 """
        self.binance.logger_info(f"{self.symbol} 交易对启动......")
        self.Initialize()
        while True:
            time.sleep(0.5)
            try:
                if not self.is_exit:
                    self.trading_close()
                    break
                self.era_run()
            except Exception:
                self.binance.logger_error(f"死循环ERROR: {traceback.format_exc()}")

                if num >= 5:
                    break
                num += 1

    def Initialize(self):
        """ 初始化: 设置杠杆与逐全仓模式 """
        if not self.binance.pan_openings["pan"]:    # 实盘时才设置
            self.binance.rest('info', 'change_leverage', symbol=self.symbol, leverage=self.binance.parameter.set_leverage)
            self.binance.rest('info', 'change_margin_type', symbol=self.symbol, marginType=self.binance.parameter.isolated)

        """ 获取交易所规则 """
        data = self.binance.rpcc_exchange_info(self.symbol)
        self.binance.parameter.this_min_qty = data["this_min_qty"]  # 订单最小数量限制
        self.binance.parameter.this_price_decimal = data["this_price_decimal"]  # 价格小数点位数
        self.binance.parameter.this_decimal = data["this_decimal"]  # 下单数量小数点位数
        self.binance.parameter.this_min_notional = data["this_min_notional"]  # 最小下单金额(交易所最小下单价格时5U)
        return

    def equal_cycle(self, timestamp: int):
        """ 判断是否等于这个周期 """
        dt = datetime.datetime.fromtimestamp(timestamp / 1000)
        if dt.minute % self.binance.parameter.interval == 0 and dt.second == 0 and dt.microsecond == 0:
            return True
        return False

    def structural_index(self, limit=1000):
        data = self.binance.rest('while_info', 'continuous_klines', pair=self.symbol, contractType="PERPETUAL",
                                 interval=f"{str(self.binance.parameter.interval)}m", limit=limit)
        data = pandas.DataFrame(data)
        data = data[[0, 2, 3, 4, 6]].astype(float)
        data.columns = ["open_time", "high", "low", "close", "close_time"]
        data["open_time"] = pandas.to_datetime(data["open_time"], unit="ms") + pandas.Timedelta(hours=8)
        data["open_time"] = data["open_time"].dt.strftime("%Y-%m-%d %H:%M:%S")
        data["ema"] = pandas_ta.ema(data["close"], self.binance.parameter.set_ema)
        data["atr"] = pandas_ta.atr(data["high"], data["low"], data["close"], self.binance.parameter.set_atr)
        data["rsi"] = pandas_ta.rsi(data["close"], self.binance.parameter.set_rsi)
        data["shang_gui"] = data["ema"] + self.binance.parameter.set_atr_multiple * data["atr"]
        data["xia_gui"] = data["ema"] - self.binance.parameter.set_atr_multiple * data["atr"]
        self.data = {
            "price": float(data["close"].values[-1]),  # 最新价格（方案二：如最新价格显示策略是亏损状态，那么可用1分钟的收盘价来开/平仓）
            "shang_gui": data["shang_gui"].values[-2],  # 上轨价格
            "xia_gui": data["xia_gui"].values[-2],  # 下轨价格
            "rsi": data["rsi"].values[-2]  # rsi值
        }
        return

    def get_pos(self):
        """
        获取持仓信息, 根据side判断是否持仓与返回持仓信息
        return True持仓/False空仓, 持仓数据, 持仓方向
        """
        if not self.binance.pan_openings["pan"]:    # 实盘
            data = self.binance.get_user_position()
            if data["number"] > 0:
                side = None
                for item in data["data"]:
                    if abs(float(item["positionAmt"])) > 0:
                        side = item["positionSide"]
                return True, data["data"], side
            return False, None, None

        else:
            if self.res_db[self.binance.parameter.db_coll_pos] > 0:
                return True, self.res_db, self.res_db[self.binance.parameter.db_coll_side]
            return False, None, None

    def trading_close(self):
        """ 交易结束 """
        process_obj = ProcessNumber.objects.filter(exchange=self.binance.exchange_name,
                                                   strategy=self.binance.strategy_name).first()
        process_obj.process = []
        process_obj.status = '-1'
        process_obj.timestamp = now_time_stamp()
        process_obj.save()
        self.binance.logger_info(f"{self.symbol} 交易对结束.")

    def up_account(self, account):
        """ 历史已结算交易金额列表 """
        data = self.binance.cache_get(self.binance.parameter.db_coll_up)
        data.append(account)
        self.binance.cache_set(self.binance.parameter.db_coll_up, data)
